package com.greendragon.web.servlet;

import java.io.File;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Date;
import java.util.Iterator;
import java.util.List;

import javax.servlet.ServletConfig;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import net.sf.json.JSONObject;

import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.FileUploadException;
import org.apache.commons.fileupload.ProgressListener;
import org.apache.commons.fileupload.FileUploadBase.SizeLimitExceededException;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.FileCleanerCleanup;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
import org.apache.commons.io.FileCleaningTracker;
import org.apache.log4j.Logger;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.support.WebApplicationContextUtils;

import com.greendragon.control.constant.GlobalConstants;
import com.greendragon.persistence.domain.Resource;
import com.greendragon.persistence.domain.User;
import com.greendragon.persistence.enmu.ResourceType;
import com.greendragon.service.backend.IResourceBackendService;

/**
 * @author wulibin, exceptsky@gmail.com, 2011-11-19 下午02:06:35
 * 
 */
public class FileuploadServlet extends HttpServlet {
	private static final long serialVersionUID = 4838235764925571770L;
	private static Logger logger = Logger.getLogger(FileuploadServlet.class);

	private IResourceBackendService resourceService;
	private String realPath; // 项目的绝对路径
	private String savePath; // 用于存放上传文件的相对路径
	private String tempPath; // 用于存放临时文件的相对路径
	private int maxMemorySize; // 内存中最大文件大小
	private int maxFileSize; // 单个文件大小限制
	private String[] fileTypes; // 允许的文件扩展名

	public void init(ServletConfig config) throws ServletException {
		super.init(config);
		savePath = config.getInitParameter("savePath");
		realPath = getServletContext().getRealPath("/");
		tempPath = config.getInitParameter("tempPath");
		maxMemorySize = Integer.parseInt(config
				.getInitParameter("maxMemorySize"));
		maxFileSize = Integer.parseInt(config.getInitParameter("maxFileSize"));
		fileTypes = config.getInitParameter("fileTypes").split(",");
		if (!new File(realPath + "/" + tempPath).isDirectory()) {
			new File(realPath + "/" + tempPath).mkdirs();
		}
		// spring注入 resource Serice
		ServletContext servletContext = this.getServletContext();
		WebApplicationContext ctx = WebApplicationContextUtils
				.getWebApplicationContext(servletContext);
		resourceService = (IResourceBackendService) ctx
				.getBean("resourceBackendService");
	}

	@SuppressWarnings("unchecked")
	public void doPost(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		
		HttpSession session = request.getSession();
		response.setContentType("text/html;charset=utf-8");
		PrintWriter out = response.getWriter();
		
		// 登入用户才有权限上传
		User user = (User) session.getAttribute(GlobalConstants.SESSION_LOGIN_USER);
		if (null == user) {
			/**
			 * 没有登入
			 */
			out.println(newResultJSONObject(false,"1000","没有登入"));
			return;
		}
		
		String pItem = request.getParameter("item");
		if(null == pItem || pItem.length()==0){
			out.println(newResultJSONObject(false,"1001","参数错误"));
			return;
		}
		// create ServletFileUpload;
		ServletFileUpload upload = newFileupload(getServletContext());
		FileUploadListener listener = new FileUploadListener();
		session.setAttribute(user.getId() +"_"+ pItem, listener);
		upload.setProgressListener(listener);
		
		List<FileItem> items = new ArrayList<FileItem>();
		//Parse the request
		try {
			items = upload.parseRequest(request);
		} catch (FileUploadException e) {
			if (e instanceof SizeLimitExceededException) {
				/**
				 * 文件大小超出限制
				 */
				out.println(newResultJSONObject(false,"1002","文件尺寸超过规定大小"));
				return;
			}
			logger.error(e);
		}
		if (items == null || items.size() == 0) {
			out.println(newResultJSONObject(false,"1003","请选择上传文件"));
			return;
		}

		Iterator iter = items.iterator();
		while (iter.hasNext()) {
			FileItem item = (FileItem) iter.next();
			if (!item.isFormField()) {
				String filePath = item.getName();
				long fileSize = item.getSize();

				if (null == filePath || filePath.equals("") || fileSize == 0) {
					out.println(newResultJSONObject(false,"1004","不能上传空文件"));
					return;
				}
				String fileName = "";
				String fileExt = "";
				String fileFullName = filePath.substring(filePath
						.lastIndexOf("/") + 1);
				int fileExtIndex = fileFullName.lastIndexOf(".");
				if (-1 != fileExtIndex) {
					fileName = fileFullName.substring(0, fileExtIndex);
					fileExt = fileFullName.substring(fileExtIndex + 1);
				} else {
					// 无文件扩展名
					fileName = fileFullName;
				}

				if (isAllowedType(fileExt)) {
					// 存储文件
					String relativePath = savePath + "/" + user.getId();
					String absolutepath = realPath + "/" + relativePath;
					String saveFileName = System.currentTimeMillis() + "";
					// 有扩展名
					if (fileExt.length() > 0) {
						saveFileName += "." + fileExt;
					}
					if (!new File(absolutepath).isDirectory()) {
						new File(absolutepath).mkdirs();
					}

					File uploadedFile = new File(absolutepath + "/"
							+ saveFileName);
					try {
						item.write(uploadedFile);
					} catch (Exception e) {
						logger.error(e);
						out.println(newResultJSONObject(false,"1004",e.toString()));
						return;
					}
					// 存储到数据库
					Resource resource = new Resource();
					resource.setName(fileName);
					resource.setType(ResourceType.MUSIC.toString());
					resource.setAuthor(user);
					resource.setBlock(false);
					resource.setUrl(relativePath + "/" + saveFileName);
					resource.setBlock(false);
					resource.setCreatedAt(new Date());
					resourceService.add(resource);
					out.println(newResultJSONObject(true,"2000","上传成功"));
					return;
				} else {
					out.println(newResultJSONObject(false,"1005","文件格式不正确"));
					return;
				}
			}
		}
	}
	
	public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException{
		HttpSession session = request.getSession();
		response.setContentType("text/html;charset=utf-8");
		PrintWriter out = response.getWriter();
		// 登入用户才有权限上传
		User user = (User) session.getAttribute(GlobalConstants.SESSION_LOGIN_USER);
		if (null == user) {
			/**
			 * 没有登入
			 */
			out.println(newResultJSONObject(false,"1000","没有登入"));
			out.flush();
			out.close();
			return;
		}
		
		String pItem = request.getParameter("item");
		if(null == pItem || pItem.length()==0){
			out.println(newResultJSONObject(false,"1001","参数错误"));
			out.flush();
			out.close();
			return;
		}
		
		long bytesRead;
		long contentLength; 
		JSONObject jsonObject;
		
		FileUploadListener listener = (FileUploadListener)session.getAttribute(user.getId() +"_"+ pItem);
		if(null == listener){
			jsonObject = newResultJSONObject(false, "1001", "参数错误");
		}else{
			jsonObject = newResultJSONObject(true, "2001", "succ");
			bytesRead = listener.getBytesRead();
			contentLength = listener.getContentLength();
			jsonObject.element("read", bytesRead);
			jsonObject.element("length", contentLength);
		}
		out.println(jsonObject);
		out.flush();
		out.close();

	}

	private boolean isAllowedType(String ext) {
		// 无扩展名
		if (ext.length() == 0) {
			return true;
		}
		for (int i = 0; i < fileTypes.length; i++) {
			if (ext.equalsIgnoreCase(fileTypes[i])) {
				return true;
			}
		}
		return false;
	}

	private DiskFileItemFactory newDiskFileItemFactory(ServletContext context,
			File repository) {
		FileCleaningTracker fileCleaningTracker = FileCleanerCleanup
				.getFileCleaningTracker(context);
		DiskFileItemFactory factory = new DiskFileItemFactory(maxMemorySize,
				repository);
		factory.setFileCleaningTracker(fileCleaningTracker);
		return factory;
	}

	private ServletFileUpload newFileupload(ServletContext context) {
		// Create a new file upload handler
		ServletFileUpload upload = new ServletFileUpload(
				newDiskFileItemFactory(context, new File(realPath + "/"
						+ tempPath)));
		// Set overall request size constraint
		upload.setSizeMax(maxFileSize);
		upload.setHeaderEncoding("UTF-8");
		return upload;
	}

	private JSONObject newResultJSONObject(boolean status, String code, String message){
		JSONObject jsonObject = new JSONObject();
		jsonObject.element("status", status);
		jsonObject.element("code", code);
		jsonObject.element("message", message);
		return jsonObject;
		
	}
	public void setResourceService(IResourceBackendService resourceService) {
		this.resourceService = resourceService;
	}

	class FileUploadListener implements ProgressListener {
		private volatile long bytesRead = 0L, contentLength = 0L, item = 0L;
		
		public void update(long pBytesRead, long pContentLength, int pItems) {
			bytesRead = pBytesRead;
			contentLength = pContentLength;
			item = pItems;
		}

		public long getBytesRead() {
			return bytesRead;
		}

		public long getContentLength() {
			return contentLength;
		}

		public long getItem() {
			return item;
		}
	}
}
